<!-- 表单不带上传文件 -->
<template>
  <div :class="isSearchClass()">
    <el-form
      v-if="model"
      ref="form"
      :size="size"
      v-bind="$attrs"
      :model="model"
      :rules="rules"
      :validate-on-rule-change="false"
    >
      <template v-for="(item, index) in showOptions">
        <el-form-item
          v-if="!item.childern"
          :key="item.prop"
          :size="size"
          :label="item.label"
          :prop="item.prop"
          @click.native="allFun(item, index,'clickFun')"
        >
          <template>
            <component
              :is="`el-${item.type}`"
              v-model.trim="model[item.prop]"
              v-bind="item.attrs"
            />
          </template>
        </el-form-item>

        <el-form-item
          v-if="item.childern"
          :key="item.prop"
          :label="item.label"
          :size="size"
          :prop="item.prop"
        >
          <component
            :is="`el-${item.type}`"
            v-model.trim="model[item.prop]"
            v-bind="item.attrs"
            @change="allFun(item, index,'changeFun')"
          >
            <component
              :is="`el-${child.type}`"
              v-for="child in item.childern"
              :key="child.label"
              :value="child.value"
              :label="child.label"
            />
          </component>
        </el-form-item>
      </template>

      <div v-if="!isButton" class="flex-cls-direct-right" :class="$attrs.inline ? 'm-r-10':''">
        <el-button size="small" @click="$emit('update:dialogVisible', false)">{{ btnText.right }}</el-button>
        <el-button size="small" type="primary" :loading="overallLoading" @click="handleConfirm()">{{ btnText.left
        }}</el-button>
      </div>

      <all-btn v-if="allBtn.show" :button-list="allBtn.btnList" :size="allBtn.size" :scope="btnData" />

    </el-form>
  </div>

</template>

<script>
// 深拷贝
import cloneDeep from "lodash/cloneDeep";
import { mapGetters, mapMutations } from "vuex";
// 全局按钮
import AllBtn from "@/components/AllBtn/src/index.vue";
// 回车键事件
import keyupSubmit from "./mixins/keyupSubmit";

export default {
  name: "MForm",
  components: { AllBtn },
  mixins: [keyupSubmit],
  props: {
    // 在弹框表单时是编辑还是新增的类型
    formType: {
      type: String,
      default: "add"
    },
    // 弹框标题 用于 回车查询时判断使用
    dialogTitle: {
      type: String,
      default: ""
    },
    options: {
      type: Array,
      required: true
    },
    // 按钮显示文字
    btnText: {
      type: Object,
      default: () => {
        return {
          left: "保存",
          right: "取消"
        };
      }
    },
    // 在弹框表单中弹框是否显示
    visible: {
      type: Boolean,
      default: false
    },

    // 是否显示按钮
    isButton: {
      type: Boolean,
      default: false
    },
    // 是否使用全局按钮组件
    allBtn: {
      type: Object,
      default: () => {
        return {
          show: false,
          btnList: [],
          size: "mini"
        };
      }
    },
    size: {
      type: String,
      default: "small"
    }
  },
  data() {
    return {
      model: {},
      // 保存后需要缓存的内容
      cloneModel: {},
      backfill: false
    };
  },
  computed: {
    btnData() {
      if (this.allBtn.show) {
        return {
          scope: {
            row: this.model,
            search: this.handleConfirm
          }
        };
      }
      return {};
    },
    ...mapGetters(["overallLoading"]),
    // 表单需要显示的项
    showOptions() {
      return this.options.filter(op => !op.hide);
    },
    // 验证规则
    rules() {
      const r = {};
      for (let i = 0; i < this.options.length; i++) {
        const op = this.options[i] || {};
        r[op["prop"]] = op.rules;
      }
      return r;
    }
  },
  watch: {
    visible(val) {
      // 在打开弹框时根据类型确定是否需要重置表单内容
      if (val) {
        this.changeLoading(false);

        // 打开弹框对指定信息进行回填
        this.initForm();

        if (this.backfill) {
          // 需要上次提交的数据进行回填
          this.setCloneModelData();
        }
        // 将其值重置为初始值并移除校验结果
        this.resetForm();

        // 同步更新父组件获取到的子组件值(不同步 编辑后新增 浅拷贝失效??  无法直接在父组件 修改表单内容 。。。。)
        this.$emit("get-model", this.model);
      }
    }
  },
  created() {
    this.init();
  },

  methods: {
    ...mapMutations({
      changeLoading: "app/SET_OVERALL_LOADING"
    }),
    resetForm() {
      this.$refs.form.resetFields();
    },
    async init() {
      await this.initForm();
      if (this.formType === "search") {
        this.$emit("search", this.handleConfirm);
        this.$emit("get-model", this.model);
      } else {
        this.$emit("get-model", this.model);
      }
    },
    // 查询时表单自有样式
    isSearchClass() {
      if (this.formType === "search") {
        return "search-el-form";
      }
      return "";
    },
    // 是否需要回填
    isBackfill() {
      for (let i = 0; i < this.options.length; i++) {
        const { backfill, prop } = this.options[i] || {};
        // 记录需要回填的字段
        if (backfill) {
          this.cloneModel[prop] = "";
          this.backfill = true;
        }
      }
    },
    // 初始化表单获取初始值
    initForm() {
      const m = {};

      // 获取初始model中内容并确定是否需要回调
      for (let i = 0; i < this.options.length; i++) {
        const { value, backfill, prop } = this.options[i] || {};

        m[prop] = value;

        // 记录需要回填的字段
        if (backfill) {
          this.cloneModel[prop] = "";
          this.backfill = true;
        }
      }

      if (this.formType === "edit") {
        this.backfill = false;
      }
      this.model = cloneDeep(m);
    },
    // 表单提交
    handleConfirm() {
      this.$refs["form"].validate(valid => {
        if (valid) {
          this.changeLoading(true);
          this.$emit("save", this.model, this.handleConfirm);
          if (this.backfill) {
            this.cloneModelVal();
          }
        } else {
          console.log("error submit!!");
          return false;
        }
      });
    },
    allFun(item, index, fun) {
      if (typeof item[fun] === "function") {
        item[fun](item, index, this.model);
      }
    },
    // 复制model内需要保存的数据
    setCloneModelData() {
      // 是否有需要克隆的数据
      if (JSON.stringify(this.cloneModel) !== "{}") {
        // 对复制数据进行回填
        Object.keys(this.model).forEach(key => {
          if (this.cloneModel[key]) {
            this.model[key] = this.cloneModel[key];
          }
        });
      }
    },
    // 克隆表单数据
    cloneModelVal() {
      const model = cloneDeep(this.model);
      // 用于在使用弹框第二次打开是否需要回填部分值
      Object.keys(this.cloneModel).forEach(key => {
        this.cloneModel[key] = model[key];
      });
    }

  }
};
</script>

<style  lang="scss" src="./index.scss"></style>

